//! Upravljanje prekidima - niska razina


#define	_ARH_PREKIDI_C_
#include "prekidi.h"

#include "vj_sucelje.h"
#include "ispis.h"
#include "razno.h"

static char *arh_opisi_prekida[] = {
	//"exceptioni" - prekidi generirani u procesoru
	"Divide Error",
	"Debug",
	"Non Maskable Interrupt",
	"Breakpoint",
	"Overflow",
	"Out of Bounds",
	"Invalid Opcode",
	"Device Not Available",
	"Double Fault",
	"Coprocessor Segment Overrun",
	"Invalid TSS",
	"Segment Not Present",
	"Stack Fault",
	"General Protection",
	"Page Fault",
	"Unknown Exeption",
	"Coprocessor Fault",
	"Alignment Check",
	"Machine Check",
	"SIMD Fault",

	//prazno, moze i bez, ali je navedeno da brojevi odgovaraju 'id'-u
	"Intel reserved",
	"Intel reserved",
	"Intel reserved",
	"Intel reserved",
	"Intel reserved",
	"Intel reserved",
	"Intel reserved",
	"Intel reserved",
	"Intel reserved",
	"Intel reserved",
	"Intel reserved",
	"Intel reserved",

	//"irq-i" - vanjski prekidi, od 32 na dalje (treba ih tako postaviti)
	"IRQ_TIMER",
	"IRQ_KEYBOARD",
	"IRQ_SLAVE_PIC",
	"IRQ_COM2",
	"IRQ_COM1",
	"IRQ_LPT2",
	"IRQ_FLOPPY",
	"IRQ_LPT1",
	"IRQ_RT_CLOCK",
	"IRQ_MASTER_PIC",
	"IRQ_RESERVED1",
	"IRQ_RESERVED2",
	"IRQ_RESERVED3",
	"IRQ_COPROCESSOR",
	"IRQ_HARD_DISK",
	"IRQ_RESERVED4",

	//"INT n" - programski prekidi
	// treba mi samo jedan "n", preko njega cu sve funkcije pozivat,
	// ovisno o argumentima koji su proslijedjeni (na stogu)
	//odabrani n=48 (prvi slobodni)
	"Programski prekid"
};

//sucelje prema jezgri--------------------------------------------------------->
char *arh_opis_prekida (int n)
{
	if (n >= 0 && n < PREKIDI_BROJ)
		return arh_opisi_prekida[n];
	else
		return "nepoznati prekid";
}

//ove se varijable koriste u arh/prekidi.S
uint32 ***arh_stog_aktivne = NULL; //mjesto za kontekst aktivne
uint32 *arh_prekidni_stog = NULL; //pokazivac stoga za potrebe jezgrinih funkcija
void (*arh_prekidna_f)(int) = NULL; //jezgrina prekidna funkcija

//pripremi prekidni podsustav
//void arh_prekidi_inicijaliziraj(opisnikdretve_t **aktdr)
void arh_prekidi_inicijaliziraj (	void (*j_prekidnaf)(int), 
					uint32 *jstogpr,
					uint32 ***stog_aktivne)
{
	//sredi prekidne vektore, tj. IDT za x86
	idt_inicijaliziraj();

	//sredi PIT; u pocetku ne pusta nista prema procesoru
	i8259_inicijaliziraj();
	
	arh_prekidna_f = j_prekidnaf;	//prekidna funkcija
	arh_prekidni_stog = jstogpr;		//stog za j.f.
	arh_stog_aktivne = stog_aktivne;	//kontekst aktivne dretve
}

//IDT-------------------------------------------------------------------------->

//IDT opisnik prekida (koji koristi sklopovlje)
//static idt_t idt[PREKIDI_BROJ];//mogao bi i sve postaviti
static idt_t idt[256];//postavljam sve
static idtr_t idtr;

extern void (*arh_prekidne_funkcije[])(void); //definirano u "prekidi.S"

//! Inicijalizacija IDT tablice
static void idt_inicijaliziraj ()
{
	int i;
	uint32 offset;

	//postavi funkcije za prekide
	for (i = 0; i < PREKIDI_BROJ; i++) {
		offset = (uint32) arh_prekidne_funkcije[i];

		idt[i].offset_lo = offset & 0xFFFF;
		idt[i].seg_sel	= 0x08;//prvi iz IDTa (iza 0.)
		idt[i].zero	= 0;
		idt[i].type	= 0x0e;
		idt[i].dpl	= 0;
		idt[i].present	= 1;
		idt[i].offset_hi = (offset >> 16) & 0xFFFF;
	}

	//ostali su programski (iako se ne bi trebali javljati!)
	offset = (uint32) arh_prekidne_funkcije[PREKIDI_BROJ - 1];

	for (i = PREKIDI_BROJ; i < 256; i++) {
		idt[i].offset_lo = offset & 0xFFFF;
		idt[i].seg_sel	= 0x08;//prvi iz IDTa (iza 0.)
		idt[i].zero	= 0;
		idt[i].type	= 0x0e;
		idt[i].dpl	= 0;
		idt[i].present	= 1;
		idt[i].offset_hi = (offset >> 16) & 0xFFFF;
	}

	// ucitaj adresu tablice IDT u IDTR registar
	idtr.limit = sizeof(idt) - 1;
	idtr.base = idt;
	__asm__("lidt %0" : : "m" (idtr));
}

//IDT--------------------------------------------------------------------------<

//i8259 (PIC) ----------------------------------------------------------------->

//! Inicijalizacija sustava za sklopovske prekide
static void i8259_inicijaliziraj()
{
	outb(PIC1_CMD, 0x11); //pocetak inicijalizacije
	outb(PIC2_CMD, 0x11);

	outb(PIC1_DATA, IRQ_OFFSET & 0xf8); //pomak prekida za +0x20
	outb(PIC2_DATA, (IRQ_OFFSET + 8) & 0xf8); //+0x28

	outb(PIC1_DATA, 0x4); //nastavi inic.
	outb(PIC2_DATA, 0x2);

	outb(PIC1_DATA, 0x1); //8086 nacin
	outb(PIC2_DATA, 0x1);

	outb(PIC1_DATA, 0xfb); //maskiraj (ignoriraj) sve osim "slave-a"
	outb(PIC2_DATA, 0xff); //maskiraj sve (na slaveu)
	
	//sada je PIC inicijaliziran, ali se ni jedan prekid ne propusta dalje
}

void i8259_omoguci_prekid (unsigned char irq)
{
	if (irq < 8)
		outb(PIC1_DATA, inb(PIC1_DATA) & ~(1 << irq));
	else
		outb(PIC2_DATA, inb(PIC2_DATA) & ~(1 << (irq - 8)));
}

void i8259_zabrani_prekid (unsigned char irq)
{
	if (irq < 8)
		outb(PIC1_DATA, inb(PIC1_DATA) | (1 << irq));
	else
		outb(PIC2_DATA, inb(PIC2_DATA) | (1 << (irq - 8)));
}


//i8259 (PIC) -----------------------------------------------------------------<

